#include "SmartStartAlgorithm.h"
#include "OfflineOptimumAlgorithm.h"
#include <list>
#include <iostream>

SmartStartAlgorithm::SmartStartAlgorithm(list<Request> requests, int dimensions, float speed, float alpha)
{
	actual_coords = new float[dimensions];
	origin = new float[dimensions];
	this->requests = requests;
	for (int i = 0; i< dimensions; i++)
		actual_coords[i]=0;
	for (int i = 0; i< dimensions; i++)
			origin[i]=0;
	total_road = 0.0;
	actual_time = 0.0;
	this->speed = speed;
	this->dimensions = dimensions;
	this->alpha = alpha;
}

SmartStartAlgorithm::~SmartStartAlgorithm()
{
	delete [] actual_coords;
	delete [] origin;
}

list<Request> SmartStartAlgorithm::calculate() {
	list<Request>::iterator previous_request, next_request;
	list<Request> previous_cycle, next_cycle;
	float previous_time, next_time, previous_cycle_time, next_cycle_time;
	while (!requests.empty()) {
		previous_time = next_time = actual_time;
		previous_request = next_request = OLTSPInstance::get_visible_requests(requests.begin(), requests.end(), actual_time);
		previous_cycle = calculate_offline(requests.begin(), previous_request, actual_time);
		previous_cycle_time = next_cycle_time = OLTSPInstance::calculate_path_distance(previous_cycle.begin(), previous_cycle.end(), true)/speed;
		while (previous_request != requests.end() &&
			   (next_time<(next_cycle_time*alpha) ||
			   previous_request==requests.begin())) {
			previous_request = next_request;
			previous_cycle = next_cycle;
			previous_cycle_time = next_cycle_time;
			actual_time = previous_time;
			previous_time = next_time;
			next_request++;
			next_time = previous_request->release_time;
			next_cycle = calculate_offline(requests.begin(), next_request, next_time);
			next_cycle_time = OLTSPInstance::calculate_path_distance(next_cycle.begin(), next_cycle.end(), true)/speed;
		}
		//actual_time = (actual_time<=previous_cycle_time*alpha)?previous_cycle_time*alpha:actual_time;
		actual_time = (actual_time<=previous_time)?previous_time:actual_time;
		mark_requests_visited(previous_cycle.begin(), previous_cycle.end(), actual_time);
		actual_time += previous_cycle_time;
	}
	return requests_done;
}

list<Request> SmartStartAlgorithm::calculate_offline(list<Request>::iterator begin, list<Request>::iterator end, float time_offset)
{
	// calculate offline optimum on a partial list of requests
	list<Request> tempList(begin, end);
	OfflineOptimumAlgorithm offline(tempList, true, time_offset);
	tempList = offline.calculate();
	return tempList;
}

void SmartStartAlgorithm::mark_requests_visited(list<Request>::iterator start, list<Request>::iterator end, float time_offset) {
	float distance = 0.0;
	list<Request>::iterator actual_request = start;

	cout << "mark request visited ";
	while (start!=end) {
		actual_request++;
		float partial_distance = start->get_distance(*actual_request);
		distance += partial_distance;
		actual_request->visited_time = time_offset + distance/speed;
		cout << (actual_request->id)<<"("<<(actual_request->release_time)<< ":" <<(actual_request->visited_time) << ") ";
		requests.remove(*actual_request);
		requests_done.push_back(*actual_request);
		start++;
	}
	cout << endl;
}
